package game.manager
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import game.map.PhysicalMap;
	import game.VO.TileVO;
	
	/**
	 * ...
	 * @author Kirill Pletnev
	 */
	public class MapManager extends EventDispatcher
	{
		private static const _instance:MapManager = new MapManager();
		private var _loaded:Boolean;
		
		private var _mapID:String = "defaultMap";
		private var _columnsMap:int = 100;
		private var _rowsMap:int = 100;
		private var _backgroundTextureURL:String = "dirt_tile.png";
		// key = position on map (tile index);
		private var _mapTiles:Vector.<TileVO>;
		private var _numTiles:uint = 0;
		
		public function MapManager()
		{
			if (_instance == null)
			{
				_mapTiles = new Vector.<TileVO>(_columnsMap * _rowsMap);
			}
			else
			{
				throw new Error("TemplateTileManager instance already existing in Singleton");
			}
		}
		
		static public function get instance():MapManager
		{
			return _instance;
		}
		
		public function addMapTile(tileVO:TileVO):void
		{
			var tileIndex:int = PhysicalMap.getTileIndex(tileVO.columnPosition, tileVO.rowPosition, _columnsMap, _rowsMap);
			
			if (tileIndex != -1)
			{
				_mapTiles[tileIndex] = tileVO;
				_numTiles++;
			}
		}
		
		public function removeMapTile(tileIndex:int):void
		{
			if (tileIndex != -1)
			{
				_mapTiles[tileIndex] = null;
				_numTiles--;
			}
		}
		
		public function getMapTile(tileIndex:int):TileVO
		{
			if (tileIndex != -1)
			{
				return _mapTiles[tileIndex];
			}
			else
			{
				return null;
			}
		}
		
		// SERIALIZATION ========================================================================
		public function serialize(data:ByteArray):void
		{
			data.writeUTF(mapID);
			data.writeUTF(backgroundTextureURL);
			data.writeUnsignedInt(_columnsMap);
			data.writeUnsignedInt(_rowsMap);
			
			data.writeUnsignedInt(_numTiles);
			
			for each (var tileVO:TileVO in _mapTiles)
			{
				if (tileVO != null)
				{
					tileVO.serialize(data);
				}
			}
		}
		
		public function deserialize(data:ByteArray):void
		{
			try
			{
				_mapID = data.readUTF();
				_backgroundTextureURL = data.readUTF();
				_columnsMap = data.readUnsignedInt();
				_rowsMap = data.readUnsignedInt();
				
				var numTiles:uint = data.readUnsignedInt();
				
				var tileVO:TileVO;
				for (var i:uint = 0; i < numTiles; i++)
				{
					tileVO = TileVO.deserialize(data);
					addMapTile(tileVO);
				}
			}
			catch (error:Error)
			{
				trace("ERROR: deserialize tile manager");
				trace(error.getStackTrace());
			}
		}
		
		// LOAD MAP ==============================================================================		
		public function loadAll(fileUrl:String):void
		{
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onLoadedMap);
			loader.addEventListener(IOErrorEvent.IO_ERROR, errorLoadMap);
			loader.dataFormat = URLLoaderDataFormat.BINARY;
			loader.load(new URLRequest(fileUrl));
		}
		
		private function onLoadedMap(e:Event):void
		{
			var loader:URLLoader = e.target as URLLoader;
			var data:ByteArray = ByteArray(loader.data);
			deserialize(data);
			finishLoading();
			
			loader.removeEventListener(Event.COMPLETE, onLoadedMap);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, errorLoadMap);
		}
		
		private function errorLoadMap(e:IOErrorEvent):void
		{
			trace("[ERROR]: Had problem loading the map file.");
			trace(e.toString());
			
			throw new Error("Had problem loading the map file.");
		}
		
		private function finishLoading():void
		{
			_loaded = true;
			dispatchEvent(new Event(Event.COMPLETE));
		}
		
		// GETTERS & SETTERS =====================================================================
		public function get columnsMap():int
		{
			return _columnsMap;
		}
		
		public function get rowsMap():int
		{
			return _rowsMap;
		}
		
		public function get backgroundTextureURL():String
		{
			return _backgroundTextureURL;
		}
		
		public function get mapID():String
		{
			return _mapID;
		}
		
		public function get loaded():Boolean
		{
			return _loaded;
		}
		
		public function get mapTiles():Vector.<TileVO>
		{
			return _mapTiles;
		}
		
		public function get numTiles():uint
		{
			return _numTiles;
		}
	}
}